import { TMessageFunc } from "../const/BaseDefine";
import { IMessage } from "../message/IMessage";
import { IEvent } from "./IEvent";

/**
 * 事件声明接口
 */
export class EventMgr {
    private static _instance: EventMgr;

    /**事件映射表 */
    public _eventMap: Map<string, IEvent[]> = new Map();

    public static getInstance() {
        if (this._instance === void 0) {
            this._instance = new EventMgr();
        }
        return this._instance;
    }

    /**
     * 检查指定事件是否已注册回调
     * @param name
     * @param cb
     * @param target
     * @returns
     */
    hasEventListener(name: string, cb: TMessageFunc, target?: any): boolean {
        const eventList = this._eventMap.get(name);
        if (eventList == null) {
            return false;
        }

        for (const k in eventList) {
            const event = eventList[k];
            if (event.cb == cb && event.target == target) {
                return true;
            }
        }

        return false;
    }

    /**
     * 注册事件
     * @param name 事件名
     * @param cb 处理事件的回调函数
     * @param target 事件目标对象
     */
    on(name: string, cb: TMessageFunc, target?: any) {
        if (!this.hasEventListener(name, cb, target)) {
            if (!this._eventMap.has(name)) {
                this._eventMap.set(name, []);
            }
            const eventList = this._eventMap.get(name);
            eventList?.push({
                name: name,
                cb: cb,
                target: target,
            });
        }
    }

    /**
     * 注销事件
     * @param type
     * @param cb
     * @param target
     */
    off(name: string, cb: TMessageFunc, target?: any) {
        const eventList = this._eventMap.get(name);
        if (eventList != null) {
            for (const k in eventList) {
                const event = eventList[k];
                if (event.cb == cb && event.target == target) {
                    delete eventList[k];
                    break;
                }
            }
        }
    }

    /**
     * 派发一个指定事件，并传递需要的参数
     * @param name
     * @param msg
     */
    emit(name: string, msg: IMessage) {
        const eventList = this._eventMap.get(name);
        if (eventList != null) {
            for (const k in eventList) {
                const event = eventList[k];
                if (event.target && event.cb) {
                    event.cb.apply(event.target, [msg]);
                }
            }
        }
    }
}
